﻿using System;
using System.IO;
using System.Collections.Generic;

namespace Kostas.K_Lib.IO
{
	public class K_Directory : IComparable<K_Directory>
	{
		// fields
		private static DateTime lastOutput = DateTime.MinValue;

		// properties
		public DirectoryInfo Info
		{
			get { return directoryInfo; }
		}
		private readonly DirectoryInfo directoryInfo;

		public long Size
		{
			get { return size > -1 ? size : size = ComputeSize(); }
		}
		private long size = -1;

		public long FullSize
		{
			get { return fullSize > -1 ? fullSize : fullSize = ComputeFullSize(); }
		}
		private long fullSize = -1;

		public List<K_Directory> Children
		{
			get
			{
				if (children == null)
					LoadChildren();
				return children;
			}
		}
		private List<K_Directory> children;

		// constructors
		public K_Directory(string path) : this(new DirectoryInfo(path)) {}

		public K_Directory(DirectoryInfo directoryInfo)
		{
			if (!directoryInfo.Exists)
				throw new DirectoryNotFoundException();
			this.directoryInfo = directoryInfo;
		}

		// methods
		private static bool AllowOutput()
		{
			DateTime now = DateTime.Now;
			double elapsed = (now - lastOutput).TotalMilliseconds;
			if (elapsed < 500)
				return false;
			else
			{
				lastOutput = now;
				return true;
			}
		}

		private long ComputeSize()
		{
			if (K_Lib.Verbosity == Verbosity.Verbose && AllowOutput())
				Console.WriteLine("Computing " + directoryInfo.FullName);
			long result = 1;
			FileInfo[] files = directoryInfo.GetFiles();
			for (int i = 0; i < files.Length; i++)
				result += files[i].Length;
			return result;
		}

		private long ComputeFullSize()
		{
			long result = 0;
			foreach (K_Directory child in Children)
				result += child.Size;
			return result;
		}

		private void LoadChildren()
		{
			if (K_Lib.Verbosity == Verbosity.Verbose && AllowOutput())
				Console.WriteLine("Reading " + directoryInfo.FullName);
			children = new List<K_Directory>();
			children.Add(this);
			DirectoryInfo[] directories = directoryInfo.GetDirectories();
			for (int i = 0; i < directories.Length; i++)
				children.AddRange(new K_Directory(directories[i]).Children);
		}

		int IComparable<K_Directory>.CompareTo(K_Directory other)
		{
			if (FullSize > other.FullSize)
				return -1;
			else if (FullSize < other.FullSize)
				return 1;
			else
				return 0;
		}
	}
}
